Exercise 06.1 (selecting and passing data structures)

The exercise in Activity 04 that involved computing the area of a triangle involved a function with six arguments ($x$ and $y$ components of each vertex). With six arguments, the likelihood of a user passing arguments in the wrong order is high.

Use an appropriate data structure to develop a new version of the function with a simpler interface (the interface is the arguments that are passed to the function). Add appropriate checks inside your function to validate the input data.


In [1]:
def area(p0, p1, p2):
    "Calculate the area of a triangle given three points coordinates in the format (x, y)"
    # Check if all the points have two coordinates
    if len(p0) == 2 and len(p1) == 2 and len(p2) == 2:
        return abs((p0[0]*(p1[1]-p2[1]) + p1[0]*(p2[1]-p0[1]) + p2[0]*(p0[1]-p1[1])) / 2)
    else:
        return 'Insert the coordinates of three points in the format (x, y)'

# Test cases
print(area((0, 0), (1, 0), (0, 1))) # 0.5
print(area((0, 0), (5, 0), (0, 8))) # 20
print(area((0, 0), (5, 1, 0), (0, 8))) # Error message


0.5
20.0
Insert the coordinates of three points in the format (x, y)

Exercise 06.2 (selecting data structures)

For a simple (non-intersecting) polygon with $n$ vertices, $(x_0, y_0)$, $(x_1, y_1)$, . . , $(x_{n-1}, y_{n-1})$, the area $A$ is given by

$$ A = \left| \frac{1}{2} \sum_{i=0}^{n-1} \left(x_{i} y _{i+1} - x_{i+1} y_{i} \right) \right| $$

and where $(x_n, y_n) = (x_0, y_0)$. The vertices should be ordered as you move around the polygon.

Write a function that computes the area of a simple polygon with an arbitrary number of vertices. Test your function for some simple shapes. Pay careful attention to the range of any loops.


In [3]:
def polygon_area(points):
    """Calculate the area of a simple polygon given a tuple of points in the format (x, y).
        The points have to be ordered as you move around the polygon"""
    # Initialize area to 0
    area = 0
    
    # For each point check the number of coordinates and add to the area
    for i in range(len(points)):
        if len(points[i]) == 2:
            # Here I use modulo to restart from 0 to account for the term where i=n-1
            area += points[i][0]*points[(i+1)%len(points)][1] - points[(i+1)%len(points)][0]*points[i][1]
        else:
            return 'The coordinates of the points should be in the format (x, y)'
    
    return abs(area/2)

# Test cases
print(polygon_area(((0, 0), (1, 0), (0, 1)))) # triangle, area = 0.5
print(polygon_area(((0, 0), (1, 0), (1, 1), (0, 1)))) # square, area = 1


0.5
1.0

Exercise 06.3 (indexing)

Write a function that uses list indexing to add two vectors of arbitrary length, and returns the new vector. Include a check that the vector sizes match, and print a warning message if there is a size mismatch. The more error information you provide, the easier it would be for someone using your function to debug their code.

Add some tests of your code.

Hint: You can create a list of zeros of length n by

z = [0]*n

In [5]:
def add_vec(x, y):
    "Sum two vectors of arbitrary length"
    # Check if the vectors have the same length
    if len(x) == len(y):
        
        # Initialize sum to zero
        z = [0]*len(x)
        
        # Add vectors element by element
        for i in range(len(x)):
            z[i] = x[i] + y[i]
        
        return z
    else:
        return 'The two vectors must have the same length'

# Test cases
print(add_vec((1, 4), (2, -3)))
print(add_vec((1, 4), (2, -3, 1))) # Error message
print(add_vec((1, 4, -5, 9), (2, -3, 1, 7)))


[3, 1]
The two vectors must have the same length
[3, 1, -4, 16]

Optional (advanced): Try writing a one-line version of this operation using list comprehension and the built-in function zip.


In [6]:
def add_vec2(x, y):
    "Sum two vectors of arbitrary length using list comprehension"
    # Check if the vectors have the same length
    if len(x) == len(y):
        # Create a new list summing the two vectors element-wise
        return [a + b for a, b in zip(x, y)]
    else:
        return 'The two vectors must have the same size'

# Test cases
print(add_vec2((1, 4), (2, -3)))
print(add_vec2((1, 4), (2, -3, 1))) # Error message
print(add_vec2((1, 4, -5, 9), (2, -3, 1, 7)))


[3, 1]
The two vectors must have the same size
[3, 1, -4, 16]

Exercise 06.4 (dictionaries)

Create a dictionary that maps college names (the key) to college abbreviations for at least 5 colleges (you can find abbreviations at https://en.wikipedia.org/wiki/Colleges_of_the_University_of_Cambridge#Colleges). From the dictionary, produce and print

  1. A dictionary from college abbreviation to name; and
  2. A list of college abbreviations sorted into alphabetical order.

In [5]:
# Colleges dictionary
colleges = {'Christ\'s':'CHR'
            , 'Churchill':'CHU'
            , 'Clare':'CL'
            , 'Clare Hall':'CLH'
            , 'Corpus Christi':'CC'
            , 'Darwin':'DAR'
            , 'Downing':'DOW'
            , 'Emmanuel':'EM'
            , 'Fitzwilliam':'F'
            , 'Girton':'G'
           }

# Check the dictionary
print('Colleges dictionary:\n', colleges)

# Initialize empty abbreviation dictionary
colleges_abbr = {}

# Populate dictionary
for name, abbr in colleges.items():
    colleges_abbr[abbr] = name

# Check the abbreviations dictionary
print('\nColleges\' abbreviations dictionary:\n', colleges_abbr)

# Sort the abbreviations
colleges_abbr_sorted = sorted(colleges_abbr)

# Check the sorted abbreviations
print('\nSorted colleges abbreviation:\n', colleges_abbr_sorted)


Colleges dictionary:
 {"Christ's": 'CHR', 'Churchill': 'CHU', 'Clare': 'CL', 'Clare Hall': 'CLH', 'Corpus Christi': 'CC', 'Darwin': 'DAR', 'Downing': 'DOW', 'Emmanuel': 'EM', 'Fitzwilliam': 'F', 'Girton': 'G'}

Colleges' abbreviations dictionary:
 {'CHR': "Christ's", 'CHU': 'Churchill', 'CL': 'Clare', 'CLH': 'Clare Hall', 'CC': 'Corpus Christi', 'DAR': 'Darwin', 'DOW': 'Downing', 'EM': 'Emmanuel', 'F': 'Fitzwilliam', 'G': 'Girton'}

Sorted colleges abbreviation:
 ['CC', 'CHR', 'CHU', 'CL', 'CLH', 'DAR', 'DOW', 'EM', 'F', 'G']

Optional extension: Create a dictionary that maps college names (the key) to dictionaries of:

  • College abbreviation
  • Year of foundation
  • Total number students

For at least 5 colleges. Take the data from https://en.wikipedia.org/wiki/Colleges_of_the_University_of_Cambridge#Colleges. Using this dictionary,

  1. Find the college with the greatest number of students and print the abbreviation; and
  2. Find the oldest college, and print the number of students and the abbreviation for this college.

In [6]:
# Colleges dictionary with additional info
colleges_ext = {'Christ\'s':{'abbreviation':'CHR', 'year':1505, 'students':541}
                , 'Churchill':{'abbreviation':'CHU', 'year':1960, 'students':704}
                , 'Clare':{'abbreviation':'CL', 'year':1326, 'students':655}
                , 'Clare Hall':{'abbreviation':'CLH', 'year':1966, 'students':155}
                , 'Corpus Christi':{'abbreviation':'CC', 'year':1352, 'students':467}
                , 'Darwin':{'abbreviation':'DAR', 'year':1964, 'students':674}
                , 'Downing':{'abbreviation':'DOW', 'year':1800, 'students':623}
                , 'Emmanuel':{'abbreviation':'EM', 'year':1584, 'students':750}
                , 'Fitzwilliam':{'abbreviation':'F', 'year':1869, 'students':688}
                , 'Girton':{'abbreviation':'G', 'year':1869, 'students':677}
               }

Find the college with the greatest number of students and print the abbreviation


In [9]:
# Initialize the result
more_students = ''
# Initialize the variable that keeps track of the max number of students
n_students = 0

# Iterate over the colleges in the dict
for coll, data in colleges_ext.items():
    # If the number of students of the current college is greater than n_students
    # update n_students with the current number and more_students with the current college name
    if data['students'] > n_students:
        more_students, n_students = coll, data['students']

# Print the college with more_students
print('The college with more students is', more_students)


The college with more students is Emmanuel

Find the oldest college, and print the number of students and the abbreviation for this college


In [12]:
# Initialize the result
out = [0, '']
# Initialize the variable that keeps track of the oldest year found to an arbitrary large year
year = 2500

for coll, data in colleges_ext.items():
    # If the year of foundation of the current college is lesser than year
    # update year with the current number and out with the current college number of students and abbreviation
    if data['year'] < year:
        out, year = [data['students'], data['abbreviation']], data['year']

# Print the oldest college number of students and name
print('{} is the oldest college and it has {} students'.format(out[1], out[0]))


CL is the oldest college and it has 655 students